Skip to content

fix(library-select): drop framework libs shadowed by project headers; release v2.2.5#265

Merged
zackees merged 1 commit into
mainfrom
fix/263-bundled-fastled-dup
May 23, 2026
Merged

fix(library-select): drop framework libs shadowed by project headers; release v2.2.5#265
zackees merged 1 commit into
mainfrom
fix/263-bundled-fastled-dup

Conversation

@zackees
Copy link
Copy Markdown
Member

@zackees zackees commented May 23, 2026

Closes #263. Cuts release v2.2.5.

The regression

fbuild 2.2.4 broke ALL teensy41 examples on FastLED's CI: every example link-fails with multiple-definition errors on every FastLED symbol. The bundled FastLED at cores/teensy4/.../libraries/FastLED/ gets compiled into the build alongside the user's local FastLED.

Root cause: the LDF resolver introduced in PR #237 (perf(library-select): parallel BFS walker) can select the framework's bundled FastLED when the user's project ships its own. The bundled library's source files get appended to core_sources (teensy/orchestrator.rs:207) and produce duplicate symbols at link.

Path-prefix attribution in fbuild-library-select::resolve mis-attributes a transitive #include resolving into the bundled library — even though the user's project owns FastLED.h directly.

The fix

New filter_framework_libs_shadowed_by_project(libraries, roots) in framework_libs.rs drops any framework library whose primary header (<lib_name>.h) is shadowed by a same-basename header under the project's include roots. Applied at the start of both the cached and non-cached resolver paths.

Conservative: only drops a library when the project ships a header matching the library's canonical name. SPI, Wire, OctoWS2811, etc. are unaffected.

Tests

  • project_is_the_library_does_not_pull_in_bundled_copy — simpler case (project src/FastLED.h, framework libraries/FastLED/). Passed before too (the resolver's path-prefix attribution handles it) but stays as a regression gate.
  • example_only_root_does_not_pull_in_bundled_fastled_when_user_owns_fastled — the failing case. Filter drops the bundled library before the resolver runs.

Release v2.2.5

Patch release rolling up:

Cargo.toml + pyproject.toml bumped to 2.2.5. On merge, release-auto.yml triggers automatically (paths include Cargo.toml and pyproject.toml).

Test plan

  • soldr cargo check --workspace --all-targets — clean
  • soldr cargo clippy --workspace --all-targets -- -D warnings — clean
  • soldr cargo fmt --all -- --check — clean
  • soldr cargo test --workspace — all green, includes both new regression tests
  • CI passes on this PR
  • release-auto.yml ships v2.2.5 to PyPI + GitHub
  • FastLED's teensy41 CI workflow goes green on fbuild==2.2.5

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes v2.2.5

  • Bug Fixes

    • Enhanced framework library selection logic with defensive filtering to prevent bundled libraries from being selected when user projects provide headers with matching names, ensuring correct library resolution.
  • Tests

    • Added test coverage for framework library shadowing scenarios across different include path configurations.
  • Chores

    • Released version 2.2.5.

Review Change Stack

… release v2.2.5

Closes #263.

## The regression

fbuild 2.2.4 broke ALL teensy41 examples on FastLED's CI: every example
link-fails with multiple-definition errors on every FastLED symbol.

Root cause: the LDF resolver (introduced as `perf(library-select)` in
PR #237) selects the framework's bundled FastLED library at
`cores/teensy4/.../libraries/FastLED/` even when the user's project
ships its own FastLED. The bundled library's source files get appended
to `core_sources` (teensy orchestrator.rs:207), get compiled into the
build, and produce duplicate symbols at link time.

The path-prefix attribution in `fbuild-library-select::resolve` can
mis-attribute a `#include <FastLED.h>` when the user's transitive
includes resolve into the bundled library — even though the user's
project owns `FastLED.h` directly.

## The fix

New `filter_framework_libs_shadowed_by_project(libraries, roots)` in
`framework_libs.rs` drops any framework library whose primary header
(`<lib_name>.h`) is shadowed by a same-basename header anywhere under
the project's include roots. Applied at the start of both the cached
and non-cached resolver paths.

Conservative: only drops a library when the project itself ships a
header matching the library's canonical name. Other framework
libraries (SPI, Wire, etc.) are unaffected.

## Tests

- `project_is_the_library_does_not_pull_in_bundled_copy` — the
  simpler case (project src/FastLED.h, framework libraries/FastLED/);
  passed before the fix too (the resolver handled this case via
  path-prefix attribution) but stays as a regression gate.
- `example_only_root_does_not_pull_in_bundled_fastled_when_user_owns_fastled`
  — the failing case (per-example walker root doesn't see the repo's
  src/, but the user owns FastLED at a higher level). Demonstrates the
  filter dropping the bundled library before the resolver runs.

Full workspace cargo check / clippy / fmt / test all green.

## Release v2.2.5

Patch release rolling up:
- THIS fix (#263 regression repair)
- The LTO-tmpdir fix from #261 / PR #262 (Windows MSYS `mv` path collapse)

Cargo.toml + pyproject.toml bumped to 2.2.5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dac75c07-edf4-4bd2-a9b0-623787de6bd3

📥 Commits

Reviewing files that changed from the base of the PR and between 98fbb8d and 17eb750.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • Cargo.toml
  • crates/fbuild-build/src/framework_libs.rs
  • pyproject.toml

📝 Walkthrough

Walkthrough

Version 2.2.5 release adds a defensive filtering step to framework library source resolution. The resolver now drops bundled framework libraries when the project provides headers with matching canonical names, preventing unintended duplication of headers like FastLED.h when users shadow bundled copies.

Changes

Framework Library Shadowing and Version Release

Layer / File(s) Summary
Version metadata updates
Cargo.toml, pyproject.toml
Workspace and project versions incremented from 2.2.4 to 2.2.5.
Core shadowing filter logic and helpers
crates/fbuild-build/src/framework_libs.rs
New public function filter_framework_libs_shadowed_by_project drops framework libraries whose primary header (<lib_name>.h, case-insensitive) matches basenames found in project shadowing roots. Helper function collect_header_basenames walks shadowing root entries and aggregates lowercased header file basenames (.h/.hh/.hpp/.hxx extensions).
Integration into library resolution paths
crates/fbuild-build/src/framework_libs.rs
Shadowing filter applied in resolve_framework_library_sources, the cached resolution helper (short-circuiting when all libraries are filtered), and cache backend error fallback path.
Regression tests for shadowing behavior
crates/fbuild-build/src/framework_libs.rs
Two test scenarios verify bundled FastLED library is not selected when project FastLED.h shadows it: direct ownership within resolver roots and ownership in explicit shadowing roots outside walker scope.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • FastLED/fbuild#263: This PR directly addresses the bundled-FastLED duplication regression by implementing the shadowing filter that drops framework libraries when project headers shadow them.
  • FastLED/FastLED#2403: The shadowing filter implementation aligns with the upstream FastLED framework shadowing fix for preferred project-local copies.

Possibly related PRs

  • FastLED/fbuild#203: Refines the same crates/fbuild-build/src/framework_libs.rs module by extending the framework library source resolution logic with the new shadowing filter checkpoint.

Poem

🐰 A header in your hand
Beats a bundled lib in sand,
The filter now sees when you own the way—
No duplication shall come to stay! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: fixing library selection to drop framework libraries shadowed by project headers, with a version bump to 2.2.5.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/263-bundled-fastled-dup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@zackees zackees merged commit 48bf377 into main May 23, 2026
86 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

teensy41 regression in 2.2.4: bundled FastLED from Teensy core/ is compiled alongside local lib → multiple definition errors for every example

1 participant